package com.fintech.pangu.elasticsearch.autoconfigure;

import com.fintech.pangu.elasticsearch.annotation.EnableElasticSearch;
import com.fintech.pangu.elasticsearch.service.AggregationService;
import com.fintech.pangu.elasticsearch.service.AnalyzeService;
import com.fintech.pangu.elasticsearch.service.DocumentService;
import com.fintech.pangu.elasticsearch.service.IndexService;
import com.fintech.pangu.elasticsearch.service.impl.AggregationServiceImpl;
import com.fintech.pangu.elasticsearch.service.impl.AnalyzeServiceImpl;
import com.fintech.pangu.elasticsearch.service.impl.DocumentServiceImpl;
import com.fintech.pangu.elasticsearch.service.impl.IndexServiceImpl;
import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Set;

/**
 * @author xujunqi
 * @since 1.0.0
 */
@Configuration
@ConditionalOnBean(annotation = EnableElasticSearch.class)
@ConditionalOnProperty(prefix = "pangu.elasticsearch", name = "enable", matchIfMissing = true)
@ConditionalOnClass({TransportClient.class, PreBuiltTransportClient.class})
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchAutoConfiguration.class);

    static {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }

    @Bean(name = "transportClient", destroyMethod = "close")
    public TransportClient transportClient(ElasticsearchProperties properties) {
        logger.info("开始ElasticSearch TransportClient配置加载");
        TransportClient client = null;

        String[] hostPortArray = properties.getHosts();
        if (hostPortArray.length == 0) {
            logger.error("ElasticSearch配置加载失败, 未配置ElasticSearch服务端对应的hosts地址");
            return null;
        }

        /**
         * 解析settings属性设置
         */
        Settings settings = Settings.EMPTY;
        if (!properties.getSettings().isEmpty()) {
            Settings.Builder builder = Settings.builder();
            Set<String> keySet = properties.getSettings().keySet();
            for (String key : keySet) {
                builder.put(key, properties.getSettings().get(key));
            }
            settings = builder.build();
        }

        try {
            client = new PreBuiltTransportClient(settings);
            String[] hostPort;
            for (String hostPortItem : hostPortArray) {
                hostPort = hostPortItem.split(":");
                if (hostPort.length != 2) {
                    logger.warn("ElasticSearch TransportClient增加client非法的host格式[{}]", hostPortItem);
                    continue;
                }
                client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(hostPort[0]), Integer.parseInt(hostPort[1])));
                logger.debug("ElasticSearch TransportClient增加client[{}]成功", hostPortItem);
            }
            logger.info("ElasticSearch TransportClient配置加载成功", Arrays.toString(hostPortArray));
        } catch (UnknownHostException e) {
            logger.error("ElasticSearch配置加载异常, 未知的host地址");
        }

        return client;
    }

    @Bean(name = "indicesAdminClient")
    public IndicesAdminClient indicesAdminClient(TransportClient client) {
        return client.admin().indices();
    }

    @Bean(name = "clusterAdminClient")
    public ClusterAdminClient clusterAdminClient(TransportClient client) {
        return client.admin().cluster();
    }

    @Bean(name = "indexService")
    public IndexService indexService(IndicesAdminClient indicesAdminClient) {
        return new IndexServiceImpl(indicesAdminClient);
    }

    @Bean(name = "documentService")
    public DocumentService documentService(TransportClient transportClient, IndexService indexService) {
        return new DocumentServiceImpl(transportClient, indexService);
    }

    @Bean(name = "aggregationService")
    public AggregationService aggregationService(TransportClient transportClient) {
        return new AggregationServiceImpl(transportClient);
    }

    @Bean(name = "analyzeService")
    public AnalyzeService analyzeService(IndicesAdminClient indicesAdminClient) {
        return new AnalyzeServiceImpl(indicesAdminClient);
    }
}
